package de.uni.muenster.idw2.autoverbal.data;

import java.util.ArrayList;

import de.uni.muenster.idw2.data.Edge;
import de.uni.muenster.idw2.data.Vertex;


public class ChoremeRoute {

  private ArrayList<Choreme> choremes;

  public ChoremeRoute(){
	  this.choremes=new ArrayList<Choreme>();
  }
  
  public Integer getLength() {
	  return choremes.size();
  }

  public Choreme getChoreme(Integer position) {
	  return this.choremes.get(position.intValue());
  }

  public void setChoreme(Integer position, Choreme choreme) {
	  this.choremes.set(position.intValue(), choreme);
  }
  
  public void addChoreme(Choreme choreme) {
	  this.choremes.add(choreme);
  }
  
  
  
  public ArrayList<Choreme> getChoremes() {
	return choremes;
}

public void setChoremes(ArrayList<Choreme> choremes) {
	this.choremes = choremes;
}

public static Pair[] chunkStraightPairs(Pair[] pairs){
	  ArrayList<Pair>	pairs2=new ArrayList<Pair>();
	  Vertex vcentral,vfirst;
	  Edge[] edges;
	  ArrayList<Edge> edges2=new ArrayList<Edge>(),intEdges;
	  int i2,i3,instruction,weight;
	  String name;
	  Pair pair;
	  
	  for(int i=0;i<pairs.length;i++){
		  edges2.clear();
		  vcentral=pairs[i].getvCentral();
		  vfirst=pairs[i].getvFirst();
		  if(pairs[i].getInstruction()!=Pair.STRAIGHT){
			  name=pairs[i].getName();
			  edges=pairs[i].getEdges();
			  instruction=pairs[i].getInstruction();
			  weight=pairs[i].getWeight();
			  intEdges=pairs[i].getIntermediateEdges();
			  for(int i4=0;i4<intEdges.size();i4++)
				  edges2.add(intEdges.get(i4));
		  }
		  else{
			  for(i2=(i+1);i2<pairs.length;i2++)
				  if(pairs[i2].getInstruction()!=Pair.STRAIGHT)
					  break;
			  name=pairs[i].getName();
			  for(i3=i;i3<(i2-1);i3++){
				  if(i3!=i)
					  name=name+"-"+pairs[i3].getName();
				  //edges2.add(pairs[i3].getEdge(0));
				  intEdges=pairs[i3].getIntermediateEdges();
				  for(int i4=0;i4<intEdges.size();i4++)
					  edges2.add(intEdges.get(i4));
				  if(pairs[i3].getEdges().length>1)
					  edges2.add(pairs[i3].getEdge(1));
			  }
			  if(pairs[i3].getEdges().length==1){
				  edges=new Edge[1];
				  edges[0]=pairs[i].getEdge(0);
			  }
			  else{
				  edges=new Edge[2];
				  edges[0]=pairs[i].getEdge(0);
				  edges[1]=pairs[i3].getEdge(1);
			  }
			  intEdges=pairs[i3].getIntermediateEdges();
			  for(int i4=0;i4<intEdges.size();i4++)
				  edges2.add(intEdges.get(i4));
			  if(!pairs[i].getName().equals(pairs[i3].getName()))
				  name=name+"-"+pairs[i3].getName();
			  vcentral=pairs[i3].getvCentral();
			  instruction=Pair.STRAIGHT;
			  weight=1;
			  i=i3;
		  }
		  pair=new Pair(name,vcentral,edges,instruction,weight);
		  pair.setvFirst(vfirst);
		  for(i3=0;i3<edges2.size();i3++)
			  pair.addIntermediateEdge(edges2.get(i3));
		  pairs2.add(pair);
	  }
	  
	  Pair[] arrPair=new Pair[pairs2.size()];
	  return pairs2.toArray(arrPair);
  }
  
  public static ChoremeRoute generateChoreme(Pair[]	pairs){
	  ChoremeRoute route=new ChoremeRoute();
	  Choreme choreme;
	  Edge edge, edge2;
	  ArrayList<Edge> intermediateEdges;
	  Vertex[] vertices, vertices2;
	  Vertex prevVertex,nextVertex;
	  int multiplicity;
	  
	  prevVertex=pairs[0].getvFirst();
	  edge = pairs[0].getEdge(0);
	  vertices = edge.getVertices();
	  choreme = new Choreme();
	  if(prevVertex.getName().equals(vertices[0].getName())){
		  choreme.addVertex(vertices[1]);
		  choreme.addVertex(vertices[0]);// vCentral is v0
	  }
	  else{
		  choreme.addVertex(vertices[0]);
		  choreme.addVertex(vertices[1]);// vCentral is v1
	  }
	  choreme.addEdge(edge);
	  choreme.setInstruction(pairs[0].getInstruction());
	  multiplicity=1;
	  intermediateEdges=pairs[0].getIntermediateEdges();
	  if(intermediateEdges.size()>0){
		  for(int i=0;i<intermediateEdges.size();i++){
			  edge2=intermediateEdges.get(i);
			  if(prevVertex.getName().equals(edge2.getVertices()[0].getName())){
				  nextVertex=edge2.getVertices()[1];
			  }
			  else{
				  nextVertex=edge2.getVertices()[0];
			  }
			  choreme.addVertex(nextVertex);
			  choreme.addEdge(edge2);
			  prevVertex=nextVertex;
			  multiplicity++;
		  }
	  }
	  if(pairs[0].getEdges().length>1){
		  edge=pairs[0].getEdge(1);
		  if(prevVertex.getName().equals(edge.getVertices()[0].getName()))
			  nextVertex=edge.getVertices()[1];
		  else
			  nextVertex=edge.getVertices()[0];
		  choreme.addVertex(nextVertex);
		  choreme.addEdge(edge);
		  prevVertex=nextVertex;
		  multiplicity++;
	  }
	  choreme.setMultiplicity(multiplicity);
	  route.addChoreme(choreme);
	  for(int i=1;i<pairs.length;i++){
		  prevVertex=pairs[i].getvFirst();
		  edge=pairs[i].getEdge(1);
		  vertices=edge.getVertices();
		  choreme=new Choreme();
		  multiplicity=0;
		  intermediateEdges=pairs[i].getIntermediateEdges();
//		  System.out.println("i=,"+i+"intEdges.size="+intermediateEdges.size());
		  if(intermediateEdges.size()>0){
			  choreme.setIsDChoreme(true);
//			  edge2=intermediateEdges.get(0);
//			  vertices2=edge2.getVertices();
//			  choreme.addVertex(vertices2[0]);
//			  choreme.addVertex(vertices2[1]);
			  for(int i2=0;i2<intermediateEdges.size();i2++){
				  edge2=intermediateEdges.get(i2);
				  vertices2=edge2.getVertices();
				  if(prevVertex.getName().equals(vertices2[0].getName())){
					  choreme.addVertex(vertices2[0]);
					  nextVertex=vertices2[1];
				  }
				  else{
					  choreme.addVertex(vertices2[1]);
					  nextVertex=vertices2[0];
				  }
				  choreme.addEdge(edge2);
				  prevVertex=nextVertex;
				  multiplicity++;
			  }
		  }
		  if(prevVertex.getName().equals(vertices[0].getName())){
			  choreme.addVertex(vertices[0]);
			  choreme.addVertex(vertices[1]);
			  nextVertex=vertices[1];
		  }
		  else{
			  choreme.addVertex(vertices[1]);
			  choreme.addVertex(vertices[0]);
			  nextVertex=vertices[0];
		  }
		  prevVertex=nextVertex;
		  choreme.addEdge(edge);
		  multiplicity++;
		  choreme.setMultiplicity(multiplicity);
		  choreme.setInstruction(pairs[i].getInstruction());
		  route.addChoreme(choreme);
	  }
	  
	  return route;
  }
  
  public static ChoremeRoute applyDChoremeRule(ChoremeRoute routeIn){
	  ChoremeRoute routeOut=new ChoremeRoute();
	  Choreme choreme,choreme2,choreme3;
	  int i,i2,i3,nvertices,multiplicity;
	  for(i=0;i<routeIn.getLength();i++){
		  choreme=routeIn.getChoreme(i);
		  choreme2=new Choreme();
		  if(choreme.getInstruction()!=Pair.STRAIGHT){
			  // Copy choreme to choremeRoute
			  nvertices=choreme.getMultiplicity()+1;
			  for(i2=0;i2<nvertices;i2++)
				  choreme2.addVertex(choreme.getVertex(i2));
			  for(i2=0;i2<choreme.getMultiplicity();i2++)
				  choreme2.addEdge(choreme.getEdge(i2));
			  choreme2.setMultiplicity(choreme.getMultiplicity());
			  choreme2.setInstruction(choreme.getInstruction());
		  }
		  else{//choreme.getInstruction()==Pair.STRAIGHT
			  // Find non-straight choreme
			  for(i3=(i+1);i3<routeIn.getLength();i3++){
				  if(routeIn.getChoreme(i3).getInstruction()!=Pair.STRAIGHT)
					  break;
			  }
			  if(i3<routeIn.getLength()){
				    // Non-straight route found
				  	multiplicity=0;
					for(;i<i3;i++){
						choreme3=routeIn.getChoreme(i);
						nvertices=choreme3.getMultiplicity()+1;
						for(i2=0;i2<(nvertices-1);i2++)
							  choreme2.addVertex(choreme3.getVertex(i2));
						for(i2=0;i2<choreme3.getMultiplicity();i2++)
							choreme2.addEdge(choreme3.getEdge(i2));
						multiplicity+=choreme3.getMultiplicity();
					}
					choreme3=routeIn.getChoreme(i);
					nvertices=choreme3.getMultiplicity()+1;
					for(i2=0;i2<nvertices;i2++)
						choreme2.addVertex(choreme3.getVertex(i2));
					for(i2=0;i2<choreme3.getMultiplicity();i2++)
						choreme2.addEdge(choreme3.getEdge(i2));
					choreme2.setInstruction(choreme3.getInstruction());
					choreme2.setIsDChoreme(true);
					multiplicity++;
					choreme2.setMultiplicity(multiplicity);
			  }
			  else{
				  // Straight until end of route
				  // Copy choreme to choremeRoute
				  nvertices=choreme.getMultiplicity()+1;
				  for(i2=0;i2<nvertices;i2++)
					  choreme2.addVertex(choreme.getVertex(i2));
				  for(i2=0;i2<choreme.getMultiplicity();i2++)
					  choreme2.addEdge(choreme.getEdge(i2));
				  choreme2.setMultiplicity(choreme.getMultiplicity());
				  choreme2.setInstruction(choreme.getInstruction());
			  }
		  }
		  routeOut.addChoreme(choreme2);
	  }
	  return routeOut;
  }
  
  public static ChoremeRoute applyEChoremeRule(ChoremeRoute routeIn){
	  ChoremeRoute routeOut = new ChoremeRoute();
	  Choreme choreme, choreme2, choreme3;
	  int i, i2, i3, nvertices, multiplicity;
	  for(i=0;i<routeIn.getLength();i++){
		  choreme=routeIn.getChoreme(i);
		  choreme2=new Choreme();
		  if(choreme.isDChoreme()==true || choreme.isEChoreme()==true){
			  nvertices=choreme.getMultiplicity()+1;
			  for(i2=0;i2<nvertices;i2++)
				  choreme2.addVertex(choreme.getVertex(i2));
			  for(i2=0;i2<choreme.getMultiplicity();i2++)
				  choreme2.addEdge(choreme.getEdge(i2));
			  choreme2.setMultiplicity(choreme.getMultiplicity());
			  choreme2.setInstruction(choreme.getInstruction());
			  choreme2.setIsDChoreme(choreme.isDChoreme());
			  choreme2.setIsEChoreme(choreme.isEChoreme());
		  }
		  else if(choreme.isDChoreme()==false && choreme.isEChoreme()==false){
			  //Find similar choreme
			  for(i3=(i+1);i3<routeIn.getLength();i3++){
				  if(routeIn.getChoreme(i3).getInstruction()!=choreme.getInstruction() ||
						  (routeIn.getChoreme(i3).isDChoreme()==true ||
						   routeIn.getChoreme(i3).isEChoreme()==true))
					  break;
			  }
			  if((i3-i)>1){
				  multiplicity=0;
				  for(;i<(i3-1);i++){
				  	  choreme3=routeIn.getChoreme(i);
					  nvertices=choreme3.getMultiplicity()+1;
					  for(i2=0;i2<(nvertices-1);i2++)
						  choreme2.addVertex(choreme3.getVertex(i2));
					  for(i2=0;i2<choreme3.getMultiplicity();i2++)
						  choreme2.addEdge(choreme3.getEdge(i2));
					  multiplicity+=choreme3.getMultiplicity();
				  }
				  choreme3=routeIn.getChoreme(i);
				  nvertices=choreme3.getMultiplicity()+1;
				  for(i2=0;i2<nvertices;i2++)
					    choreme2.addVertex(choreme3.getVertex(i2));
				  for(i2=0;i2<choreme3.getMultiplicity();i2++)
					  choreme2.addEdge(choreme3.getEdge(i2));
				  multiplicity+=choreme3.getMultiplicity();
				  choreme2.setInstruction(choreme3.getInstruction());
				  choreme2.setIsEChoreme(true);
				  choreme2.setMultiplicity(multiplicity);
			  }
			  else if((i3-i)==1){
				  nvertices=choreme.getMultiplicity()+1;
				  for(i2=0;i2<nvertices;i2++)
					  choreme2.addVertex(choreme.getVertex(i2));
				  for(i2=0;i2<choreme.getMultiplicity();i2++)
					  choreme2.addEdge(choreme.getEdge(i2));
				  choreme2.setMultiplicity(choreme.getMultiplicity());
				  choreme2.setInstruction(choreme.getInstruction());
				  choreme2.setIsDChoreme(choreme.isDChoreme());
				  choreme2.setIsEChoreme(choreme.isEChoreme());
			  }
		  }
		  routeOut.addChoreme(choreme2);
	  }
	  
	  return routeOut;
  }

}